package xconsole

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"

	"gitee.com/xiaoyutab/xgotool/xstring"
)

// JSON转结构体类型
//
//	help	是否显示说明文档
func json2model(help bool) string {
	if help {
		return "根据JSON字符串生成Struct结构体"
	}
	json_file := ""
	json_name := ""
	flag.StringVar(&json_file, "file", "", "JSON文件位置，留空表示手动输入")
	flag.StringVar(&json_name, "name", "JSONStruct", "JSON转换成的结构体名称")
	flag.Parse()
	jsons := ""
	if json_file != "" {
		// 读取文件内容
		cont, err := os.ReadFile(json_file)
		if err != nil {
			panic("文件读取错误：" + err.Error())
		}
		jsons = string(cont)
	} else {
		fmt.Println("请手动输入JSON文本(为方便复制粘贴，此处采用空内容结束，即输入完成后需要按两次回车): ")
		fmt.Println("PS: 由于实现逻辑，暂不支持上下左右键仅限方向调整")
		for {
			tmp := ""
			fmt.Scanln(&tmp)
			if tmp == "" {
				// 结束
				break
			}
			jsons += tmp
		}
	}
	fmt.Println("JSON内容：" + jsons)
	var l []any
	var m map[string]any
	// JSON转GO结构体
	err := json.Unmarshal([]byte(jsons), &m)
	if err != nil {
		err := json.Unmarshal([]byte(jsons), &l)
		if err != nil {
			panic("JSON转换失败：" + err.Error())
		}
	}
	fmt.Println(json2struct(m, l, json_name, true))
	return ""
}

// JSON类型转go结构体字符串，以便输出到屏幕上
//
//	m			待转换的map结构体
//	l			待转换的list列表
//	json_name	JSON结构体名称
//	json_type	是否忽略json类型转换【true-整形转换为json.Number数字 false-整形转换成int64数字】
func json2struct(m map[string]any, l []any, json_name string, json_type bool) string {
	tmp_footer := ""
	outs := "\n\ntype " + xstring.CamelCase(json_name)
	if len(m) > 0 {
		outs += " struct {\n"
		// 结构体为一个map数组
		for k, v := range m {
			tp := any2type(v, false, json_type)
			tn := json_name + "_" + k
			if tp == "any" {
				// 如果还是复合类型变量的话
				if vv, ok := v.(map[string]any); ok {
					tp = " " + xstring.CamelCase(tn)
					tmp_footer += json2struct(vv, nil, tn, json_type)
				}
			} else if tp == "[]any" {
				// 如果还是复合类型变量的话
				if vv, ok := v.([]any); ok {
					if vvv, ok := vv[0].(map[string]any); ok {
						tp = "[]" + xstring.CamelCase(tn)
						tmp_footer += json2struct(vvv, nil, tn, json_type)
					}
				}
			}
			outs += fmt.Sprintf("\t%s\t%s\t`json:\"%s\" form:\"%s\"` \n",
				xstring.CamelCase(k), tp, k, k,
			)
		}
		outs += "}"
	} else if len(l) > 0 {
		outs += any2type(l[0], true, json_type)
	}
	return tmp_footer + "\n" + outs
}

// 根据any类型变量推断类型
//
//	inf	待推断变量
//	arr	上次推断是否为数组
//	j2	是否将数字转换为json.Number类型
func any2type(inf any, arr, j2 bool) string {
	outs := ""
	switch xstring.Any2ype(inf) {
	case 1, 2:
		if j2 {
			outs += "json.Number"
		} else {
			// 会被识别成float64类型，所以此处需要使用
			if xstring.IsInteger(inf.(float64)) {
				outs += "int64"
			} else {
				outs += "float64"
			}
		}
	case 3:
		outs += "string"
	default:
		if v, ok := inf.([]any); ok {
			outs += any2type(v[0], true, j2)
		} else {
			outs += "any"
		}
	}
	if arr {
		return "[]" + outs
	}
	return outs
}
